package stage;

import java.io.*;
import java.util.*;
import repository.Repository;
import gitobject.*;
import fileoperation.FileCreation;
import sha1.*;

public class Index {
    protected Map<String, String[]> info = new TreeMap<>();
    protected static String path;

    static {
        try {
            path = Repository.getGitDir();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * build an index object
     */
    public Index() throws IOException {
        if (!new File(path + File.separator + "index").exists()) {
            FileCreation.createFile(path, "index", "");
        } else {
            readIndex();
        }
    }

    /**
     * load from local index file
     */
    public void readIndex() throws IOException {
        File indexFile = new File(path + File.separator + "index");
        FileInputStream fis = new FileInputStream(indexFile);
        BufferedReader br = new BufferedReader(new InputStreamReader(fis));
        String line = br.readLine();
        while (line != null) {
            String[] arr = Arrays.copyOfRange(line.split(" "), 0, 3);
            String name = line.split(" ")[3];
            info.put(name, arr);
            line = br.readLine();
        }
    }

    public Map<String, String[]> getInfo() {
        return info;
    }

    /**
     * add file to stage and cache it
     */
    public void add(File file) throws Exception {
        if (!file.exists()) {
            return;
        }
        if (file.isFile()) {
            if (changed(file)) {
                Blob blob = new Blob(file);
                String[] entry = new String[3];
                entry[0] = blob.getMode();
                entry[1] = blob.getKey();
                entry[2] = String.valueOf(file.lastModified());
                String name = file.getPath().substring(Repository.getWorkTree().length()+1);
                info.put(name, entry);
            }
        }
        if (file.isDirectory()) {
            File[] fileList = file.listFiles();
            assert fileList != null;
            for (File f : fileList) {
                add(f);
            }
        }
    }

    /**
     * write to local index file
     */
    public void write() throws IOException {
        File file = new File(path + File.separator + "index");
        if (file.exists()) {
            FileOutputStream fos = new FileOutputStream(file);
            info.forEach((k, v) -> {
                try {
                    fos.write((v[0] + " " + v[1] + " " + v[2] + " " + k + "\r\n").getBytes());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
            fos.close();
        }
    }

    /**
     * check if file is modified
     */
    public boolean changed(File file) throws Exception {
        boolean change = true;
        String filePath = file.getPath();
        if (info.containsKey(filePath))
            if (info.get(filePath)[1].equals(SHA1.getHash(file)))
                change = false;
        return change;
    }

    /**
     * remove entry from index
     */
    public void remove(String fileName) throws IOException {
        if (!info.containsKey(fileName))
            System.out.println("File " + fileName + " doesn't exist in staging area.");
        else {
            info.remove(fileName);
            write();
            System.out.println("Remove file "+ fileName + " from staging area.");
        }
    }

    public void deleteAll() throws IOException {
//        File index = new File(path+File.separator+"index");
//        if(index.exists()){
//            FileOutputStream fos = new FileOutputStream(index);
//            byte[] empty = new byte[0];
//            fos.write(empty);
//            fos.close();
//        }
        info.clear();
        write();
    }

    /**
     * Reset the index to specific commit
     * @param tree tree of commit
     * @throws IOException ex
     */
    public void reset(Tree tree) throws IOException {
        deleteAll();
        tree.getTreeList().forEach((name, object) -> getBlob("", name, object));
        write();
    }

    public void getBlob(String lastPath, String name, GitObject object) {
        if (object.getFmt().equals("blob")) {
            String[] entry = new String[3];
            entry[0] = object.getMode();
            entry[1] = object.getKey();
            entry[2] = String.valueOf(object.getTime());
            info.put(lastPath + name, entry);
        } else {
            Tree tree = (Tree) object;
            tree.getTreeList().forEach((n, o) -> getBlob(lastPath + name + File.separator, n, o));
        }
    }
}